package com.yjc.drygoods.member.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.yjc.common.to.SpuHasStock;
import com.yjc.common.to.SkuInfoTo;
import com.yjc.common.to.SpuCommentCountTo;
import com.yjc.common.utils.R;
import com.yjc.common.vo.MemberRespVo;
import com.yjc.drygoods.member.dao.MemberCollectSkuDao;
import com.yjc.drygoods.member.entity.MemberCollectSkuEntity;
import com.yjc.drygoods.member.feign.OrderFeignService;
import com.yjc.drygoods.member.feign.ProductFeignService;
import com.yjc.drygoods.member.feign.WareFeignService;
import com.yjc.drygoods.member.interceptor.LoginUserInterceptor;
import com.yjc.drygoods.member.service.MemberCollectSkuService;
import com.yjc.common.vo.ConsumeAttentionCountRelationVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yjc.common.utils.PageUtils;
import com.yjc.common.utils.Query;
import org.springframework.util.StringUtils;

@Slf4j
@Service("memberCollectSkuService")
public class MemberCollectSkuServiceImpl extends ServiceImpl<MemberCollectSkuDao, MemberCollectSkuEntity> implements MemberCollectSkuService {

    @Autowired
    ThreadPoolExecutor threadPool;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    WareFeignService wareFeignService;

    @Autowired
    OrderFeignService orderFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberCollectSkuEntity> page = this.page(
                new Query<MemberCollectSkuEntity>().getPage(params),
                new QueryWrapper<MemberCollectSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils getTotalFollowProductInfo(Map<String, Object> params) throws ExecutionException, InterruptedException {
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        Long memberId = memberRespVo.getId();
        QueryWrapper<MemberCollectSkuEntity> queryWrapper = new QueryWrapper<MemberCollectSkuEntity>().eq("member_id", memberId);
        params.put("limit", "8");
        String currentPage = (String) params.get("page");
        if (StringUtils.isEmpty(currentPage)) {
            params.put("page", "1");
        }
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            queryWrapper.like("sku_name", key);
        }

        IPage<MemberCollectSkuEntity> page = this.page(
                new Query<MemberCollectSkuEntity>().getPage(params),
                queryWrapper
        );

        List<MemberCollectSkuEntity> memberCollectSkus = page.getRecords();
        if (memberCollectSkus != null && memberCollectSkus.size() > 0) {
            List<Long> skuIds = memberCollectSkus.stream().map(item -> {
                return item.getSkuId();
            }).collect(Collectors.toList());
            List<Long> spuIds = memberCollectSkus.stream().map(MemberCollectSkuEntity::getSpuId).distinct().collect(Collectors.toList());


            //1.异步调用远程库存服务，查询是否有库存
            CompletableFuture<Map<Long, Boolean>> hashStockFuture = CompletableFuture.supplyAsync(() -> {
                R skuWare = wareFeignService.getSpuWare(spuIds);
                Map<Long, Boolean> hashStockMap = null;
                if (skuWare.getCode() == 0) {
                    List<SpuHasStock> spuWareDatas = skuWare.getData(new TypeReference<List<SpuHasStock>>() {
                    });
                    if (spuWareDatas != null && spuWareDatas.size() > 0) {
                        hashStockMap = spuWareDatas.stream().collect(Collectors.toMap(SpuHasStock::getSpuId, SpuHasStock::getHashStock));
                    }
                }
                return hashStockMap;
            }, threadPool);

            //2.异步调用远程商品服务，查询商品价格
            CompletableFuture<Map<Long, BigDecimal>> skuPriceFuture = CompletableFuture.supplyAsync(() -> {
                R batchSkuInfo = productFeignService.getBatchSkuInfo(skuIds);
                Map<Long, BigDecimal> skuPriceDatas = null;
                if (batchSkuInfo.getCode() == 0) {
                    List<SkuInfoTo> skuInfos = batchSkuInfo.getData(new TypeReference<List<SkuInfoTo>>() {
                    });
                    if (skuInfos != null && skuInfos.size() > 0) {
                        skuPriceDatas = skuInfos.stream().collect(Collectors.toMap(SkuInfoTo::getSkuId, SkuInfoTo::getPrice));
                    }
                }
                return skuPriceDatas;
            }, threadPool);

            //3.异步调用远程商品服务，查询商品评论数量
            CompletableFuture<Map<Long, Integer>> skuCommentCountFuture = CompletableFuture.supplyAsync(() -> {
                R batchSkuComments = productFeignService.getBatchSkuComments(skuIds);
                Map<Long, Integer> skuCommentCounts = null;
                if (batchSkuComments.getCode() == 0) {
                    List<SpuCommentCountTo> spuCommentCounts = batchSkuComments.getData(new TypeReference<List<SpuCommentCountTo>>() {
                    });
                    if (spuCommentCounts != null && spuCommentCounts.size() > 0) {
                        skuCommentCounts = spuCommentCounts.stream().collect(Collectors.toMap(SpuCommentCountTo::getSkuId, SpuCommentCountTo::getSpuCommentCount));
                    }
                }
                return skuCommentCounts;
            }, threadPool);

            //4.等待所有异步任务一齐完成
            CompletableFuture<Void> allFuture = CompletableFuture.allOf(hashStockFuture, skuPriceFuture, skuCommentCountFuture);
            allFuture.get();

            Map<Long, Boolean> hasStockMap = hashStockFuture.get();
            Map<Long, BigDecimal> skuPriceMap = skuPriceFuture.get();
            Map<Long, Integer> skuCommentMap = skuCommentCountFuture.get();

            List<MemberCollectSkuEntity> memberCollectSkusRes = memberCollectSkus.stream().map(item -> {
                item.setHasStock(hasStockMap.get(item.getSpuId()));
                log.info("hasStockMap.get(item.getSkuId()):{}",hasStockMap.get(item.getSkuId()));
                item.setPrice(skuPriceMap.get(item.getSkuId()));
                item.setCommentCount(skuCommentMap.get(item.getSkuId()));
                return item;
            }).collect(Collectors.toList());
            page.setRecords(memberCollectSkusRes);
            PageUtils pageUtils = new PageUtils(page);
            return pageUtils;
        }
        return new PageUtils(page);

    }

    @Override
    public void unfollow(Long skuId) {
        this.remove(new QueryWrapper<MemberCollectSkuEntity>().eq("sku_id", skuId));
    }

    @Override
    public List<ConsumeAttentionCountRelationVo> getComnsumeAttentionCountRelation() {

        List<ConsumeAttentionCountRelationVo> consumeAttentionCountRelations = this.baseMapper.selectAttentionCount();
        List<Long> memberIds = consumeAttentionCountRelations.stream().map(item -> {
            return item.getMemberId();
        }).collect(Collectors.toList());
        log.info("memberIds:{}", memberIds);
        log.info("consumeAttentionCountRelations:{}", consumeAttentionCountRelations);
        R r = orderFeignService.getEveryoneConsumeTotal(memberIds);
        if (r.getCode() == 0) {
            List<ConsumeAttentionCountRelationVo> data = r.getData(new TypeReference<List<ConsumeAttentionCountRelationVo>>() {
            });
            log.info("data:{}", data);
            List<ConsumeAttentionCountRelationVo> res = consumeAttentionCountRelations.stream().map(item -> {
                Map<Long, BigDecimal> collect = data.stream()
                        .filter(subitem -> subitem.getMemberId() == item.getMemberId() && subitem.getRelationTime().equals(item.getRelationTime()))
                        .collect(Collectors.toMap(ConsumeAttentionCountRelationVo::getMemberId, ConsumeAttentionCountRelationVo::getExpenditure));
                item.setExpenditure(collect.get(item.getMemberId()));
                return item;
            }).collect(Collectors.toList());
            log.info("res:{}", res);
            return res;
        }
        return null;

    }

}